import { useEffect, useRef, useState } from 'react'
import './ClipModal.scss'
import RemoveSvg from '@/svg/RemoveSvg'
import useStateRef from '@/hooks/useStateRef'
import imageLoadManager from '@/lib/imageLoadManager'
import { loadImageInfo } from '@/utils/loadVideo'
import { showLoading } from '@/utils/loading'
import CustomCanvas from '@/component/CustomCanvas'
import { imageClip } from '@/lib/imageClip'
import { useI18n } from '@/i18n'
interface Props {
  show: boolean
  onHide: () => void
  frameList: FrameInfo[]
  allFrameList: FrameInfo[]
  fps: number
  onUpdate: (frameList: FrameInfo[]) => void
}

const dragList = [
  'left',
  'top',
  'right',
  'bottom',
  'center',
  'leftTop',
  'rightTop',
  'leftBottom',
  'rightBottom',
] as const
type DragType = (typeof dragList)[number]
const edgeList = ['left', 'top', 'right', 'bottom'] as DragType[]
const cornerList = [
  'leftTop',
  'rightTop',
  'leftBottom',
  'rightBottom',
] as DragType[]
const ClipModal = ({
  show,
  onHide,
  frameList,
  allFrameList,
  fps,
  onUpdate,
}: Props) => {
  const { t } = useI18n()
  const canvasRef = useRef<HTMLCanvasElement>(null)
  const imageFrameList = useRef<HTMLImageElement[]>([])
  const canvasCtx = useRef<CanvasRenderingContext2D | null>(null)
  const [canvasSize, setCanvasSize, canvasSizeRef] = useStateRef({
    width: 200,
    height: 200,
  })
  const [rect, setRect, rectRef] = useStateRef({
    left: 0,
    top: 0,
    right: 0,
    bottom: 0,
  })
  const [canvasRealSize, setCanvasRealSize, canvasRealSizeRef] = useStateRef({
    width: 200,
    height: 200,
  })
  const canvasScale = {
    width: canvasRealSizeRef.current.width / canvasSizeRef.current.width,
    height: canvasRealSizeRef.current.height / canvasSizeRef.current.height,
  }
  useEffect(() => {
    const observer = new ResizeObserver(handleResize)
    function handleResize() {
      setCanvasRealSize({
        width: canvasRef.current.clientWidth,
        height: canvasRef.current.clientHeight,
      })
    }
    const canvas = canvasRef.current
    handleResize()
    canvas && observer.observe(canvas)
    return () => {
      observer.unobserve(canvas)
      observer.disconnect()
    }
  }, [])
  useEffect(() => {
    const task = async () => {
      if (frameList.length != 0) {
        const info = await loadImageInfo(frameList[0].url)
        setCanvasSize({
          width: info.width,
          height: info.height,
        })
        canvasRef.current.width = info.width
        canvasRef.current.height = info.height
        setRect({
          left: info.width * 0.15,
          top: info.height * 0.15,
          right: info.width * 0.85,
          bottom: info.height * 0.85,
        })
      } else {
        setCanvasSize({ width: 200, height: 200 })
        canvasRef.current.width = 200
        canvasRef.current.height = 200
        setRect({
          left: 0,
          top: 0,
          right: 200,
          bottom: 200,
        })
      }
    }
    task()
  }, [frameList])
  useEffect(() => {
    if (!show) {
      return
    }
    let isEnd = false
    const task = async () => {
      imageFrameList.current = await imageLoadManager.loadImageList(frameList)
      //   if (!play) {
      //     return
      //   }
      // 帧时间
      const frameTime = 1000 / fps
      let frame = 0
      let nowframeTime = 0
      let lastTime = 0
      canvasCtx.current = canvasRef.current.getContext('2d')
      canvasCtx.current.imageSmoothingEnabled = false
      const anim = (nowTime: number) => {
        const deltaTime = nowTime - lastTime
        lastTime = nowTime
        nowframeTime += deltaTime
        const addFrame = Math.floor(nowframeTime / frameTime)
        nowframeTime = nowframeTime % frameTime
        draw(frame)
        frame += addFrame
        if (frameList.length == 0) isEnd = true
        while (frame >= frameList.length && frameList.length != 0) {
          frame -= frameList.length
        }
        if (isEnd) return
        requestAnimationFrame(anim)
      }
      requestAnimationFrame(anim)
    }
    task()
    return () => {
      isEnd = true
    }
  }, [show, frameList, canvasSize])

  const draw = (frame = 0) => {
    if (frame < 0 || frame >= imageFrameList.current.length) {
      return
    }
    const ctx = canvasCtx.current
    if (!ctx) return
    const w = canvasSizeRef.current.width
    const h = canvasSizeRef.current.height
    ctx.clearRect(0, 0, w, h)
    if (frameList.length == 0) {
      return
    }
    const imageW = imageFrameList.current[frame].naturalWidth
    const imageH = imageFrameList.current[frame].naturalHeight
    ctx.drawImage(
      imageFrameList.current[frame],
      0,
      0,
      imageW,
      imageH,
      0,
      0,
      w,
      h
    )
  }

  async function onSave(): Promise<void> {
    const hideloading = showLoading()
    try {
      const res = await imageClip(allFrameList, rectRef.current, (cur, len) => {
        hideloading.setProgress((cur / len) * 100)
      })
      onUpdate(res)
    } catch (e) {
      console.error(e)
    } finally {
      hideloading()
    }
  }

  const [_, setDrag, drag] = useStateRef(null as DragType)

  function setScale(scale: number) {
    const w = rect.right - rect.left
    const h = rect.bottom - rect.top
    const newRect = {
      left: rect.left - (w * (scale - 1)) / 2,
      top: rect.top - (h * (scale - 1)) / 2,
      right: rect.right + (w * (scale - 1)) / 2,
      bottom: rect.bottom + (h * (scale - 1)) / 2,
    }
    setRect({
      ...newRect,
    })
  }
  return (
    <div className="ClipModal-component">
      <div className={`ClipModal ${show ? 'show' : ''}`}>
        <div className="top">
          <div className="title">
            <span>{t('canvasCutting')}</span>
          </div>
          <ripple-button className="remove" onClick={onHide}>
            <RemoveSvg />
          </ripple-button>
        </div>
        <div className="center-box">
          <div className="canvas-view">
            <CustomCanvas className="canvas" ref={canvasRef}></CustomCanvas>
            <div
              className="clip-box"
              style={{
                width: canvasRealSize.width,
                height: canvasRealSize.height,
              }}
              onWheel={(e) => {
                if (e.deltaY > 0) {
                  setScale(0.98)
                } else {
                  setScale(1.02)
                }
              }}>
              <div
                className="clip-view"
                style={{
                  width: (rect.right - rect.left) * canvasScale.width,
                  height: (rect.bottom - rect.top) * canvasScale.height,
                  left: rect.left * canvasScale.width,
                  top: rect.top * canvasScale.height,
                }}
                onMouseDown={() => {
                  setDrag('center')
                  const onMove = (e: MouseEvent) => {
                    const x = e.movementX / canvasScale.width
                    const y = e.movementY / canvasScale.height
                    rect.left += x
                    rect.top += y
                    rect.right += x
                    rect.bottom += y
                    setRect({
                      ...rect,
                    })
                  }
                  window.addEventListener('mousemove', onMove)
                  window.addEventListener(
                    'mouseup',
                    () => {
                      setDrag(null)
                      setRect({
                        left: Math.round(rect.left),
                        top: Math.round(rect.top),
                        right: Math.round(rect.right),
                        bottom: Math.round(rect.bottom),
                      })
                      window.removeEventListener('mousemove', onMove)
                    },
                    {
                      once: true,
                    }
                  )
                }}>
                {edgeList.map((item, index) => {
                  return (
                    <div
                      key={index}
                      className={`${item}`}
                      onMouseDown={(e) => {
                        if (drag.current != null) return
                        e.stopPropagation()
                        setDrag(item)
                        const onMove = (e: MouseEvent) => {
                          const x = e.movementX / canvasScale.width
                          const y = e.movementY / canvasScale.height
                          if (item == 'left') {
                            rect.left += x
                          } else if (item == 'right') {
                            rect.right += x
                          } else if (item == 'top') {
                            rect.top += y
                          } else if (item == 'bottom') {
                            rect.bottom += y
                          }
                          setRect({
                            ...rect,
                          })
                        }
                        window.addEventListener('mousemove', onMove)
                        window.addEventListener(
                          'mouseup',
                          () => {
                            setDrag(null)
                            window.removeEventListener('mousemove', onMove)
                          },
                          {
                            once: true,
                          }
                        )
                      }}></div>
                  )
                })}
                {cornerList.map((item, index) => {
                  return (
                    <div
                      key={index}
                      className={`${item}`}
                      onMouseDown={(e) => {
                        if (drag.current != null) return
                        e.stopPropagation()
                        setDrag(item)
                        const onMove = (e: MouseEvent) => {
                          const x = e.movementX / canvasScale.width
                          const y = e.movementY / canvasScale.height
                          if (item == 'leftTop') {
                            rect.left += x
                            rect.top += y
                          } else if (item == 'rightTop') {
                            rect.right += x
                            rect.top += y
                          } else if (item == 'leftBottom') {
                            rect.left += x
                            rect.bottom += y
                          } else if (item == 'rightBottom') {
                            rect.bottom += y
                            rect.right += x
                          }
                          setRect({
                            ...rect,
                          })
                        }
                        window.addEventListener('mousemove', onMove)
                        window.addEventListener(
                          'mouseup',
                          () => {
                            setDrag(null)
                            window.removeEventListener('mousemove', onMove)
                          },
                          {
                            once: true,
                          }
                        )
                      }}></div>
                  )
                })}

                <div className="cenlin"></div>
              </div>
            </div>
          </div>
          <div className="input-box">
            <div className="label">
              <label>{t('originalSize')}</label>
            </div>
            <div>{`${canvasSize.width} x ${canvasSize.height}`}</div>
          </div>
          <div className="input-box">
            <div className="label">
              <label>{t('cuttingSize')}</label>
            </div>
            <div>{`${Math.round(rect.right - rect.left)} x ${Math.round(
              rect.bottom - rect.top
            )}`}</div>
          </div>
        </div>
        <ripple-button
          style={{
            marginLeft: 'auto',
            background: 'var(--primary-color)',
            color: 'white',
            width: 'fit-content',
            padding: '8px 10px',
          }}
          onClick={onSave}>
          {t('saveChanges')}
        </ripple-button>
      </div>
      <div className={`mask ${show ? 'show' : ''}`} onClick={onHide}></div>
    </div>
  )
}

export default ClipModal
